﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using NUnit.Framework;
using SymbolIntegration.core;
using SymbolIntegration.core.Helpers;

namespace SymbolIntegration.test
{
    [TestFixture]
    class ParseTests
    {
        [TestCase(" ( (   () (   )) )")]
        [TestCase("  ((      )    )")]
        [TestCase("(( (( ))) )    ")]
        [TestCase("((() (( ( ))( ))) )  ()   ")]
        [Test]
        public void CheckScopes_ResultSucceed_Test(string expression)
        {
            int error;
            bool result = ParseUtils.CheckScopes(expression, out error);
            Assert.IsTrue(result, "Error on" + error + "position");
        }

        [TestCase(" ( (     )")]
        [TestCase("((  (    )    )")]
        [TestCase("(   (  ) ) ( ))")]
        [TestCase("( (  ) ) )( (  )")]
        [TestCase("(( (( )())) )    )    )")]
        [Test]
        public void CheckScopes_ResultFailed_Test(string expression)
        {
            int error;
            bool result = ParseUtils.CheckScopes(expression, out error);
            Assert.IsFalse(result, "Error on" + error + "position");
        }

        [TestCase(" (      )")]
        [TestCase("((      )    )")]
        [TestCase("(( (( ))) )    )    )")]
        [Test]
        public void FindCloseScopePosition_ResultIs8_Test(string expression)
        {
            const int position = 1;
            int size = expression.Length;
            int result = ParseUtils.FindCloseScopePosition(expression, position, size);
            Assert.AreEqual(8, result);
        }

        [TestCase("((  ( (   ) )))")]
        [TestCase("  ((  ( (   ) )))")]
        [TestCase("( () )    ")]
        [TestCase("( )")]
        [Test]
        public void TrimScopes_ResultIsEmpty_Test(string expression)
        {
            int position = 0, size = expression.Length;
            ParseUtils.TrimScopes(expression, ref position, ref size);
            Assert.AreEqual("", expression.Substring(position, size));
        }

        [TestCase("((  ( (  123 ) )))")]
        [TestCase("  ((  ( ( 79797  ) )))")]
        [TestCase("( (33 ) )    ")]
        [TestCase("(23 )")]
        [Test]
        public void TrimScopes_ResultNumber_Test(string expression)
        {
            int position = 0, size = expression.Length;
            ParseUtils.TrimScopes(expression, ref position, ref size);
            var number = expression.Substring(position, size);
            Assert.IsTrue(number.All(char.IsNumber), "result is " + number);

        }
        [TestCase("((  ( (  123 + 11 ) )))")]
        [TestCase(" 1+ ((  ( ( 79797  ) )))")]
        [TestCase("(3 + 33 * 2  )    ")]
        [TestCase("(23 + 11 )")]
        [Test]
        public void ParseExpression_ResultIsAddends_Test(string expression)
        {
            var addends = ParseUtils.ParseExpression(expression);

            Assert.AreEqual(ExpressionType.Addends, addends.Type);
        }

        [TestCase("((  ( (  123 * 11 ) )))")]
        [TestCase(" 1 ^ 8 * ((  ( ( 79797  ) )))")]
        [TestCase("( (3 + 33) * 2 )     ")]
        [TestCase("(23 * 11 )")]
        [Test]
        public void ParseExpression_ResultIsMultiplier_Test(string expression)
        {
            var mult = ParseUtils.ParseExpression(expression);

            Assert.AreEqual(ExpressionType.Multipliers, mult.Type);
        }

        [TestCase("((  ( (  123 ^ 11 ) )))")]
        [TestCase(" 1 ^ (8 * ((  ( tg( 79797  ) ))))")]
        [TestCase("( sin(3 + 33) ^ 2 )     ")]
        [TestCase("(23 ^ 11 )")]
        [Test]
        public void ParseExpression_ResultIsPower_Test(string expression)
        {
            var pow = ParseUtils.ParseExpression(expression);

            Assert.AreEqual(ExpressionType.Power, pow.Type);
        }
        [TestCase("(( cos ( (  123 ^ 11 )) ))")]
        [TestCase(" sin (1 ^ (8 * ((  ( ( 79797  ) )))))")]
        [TestCase("  ( ln( (3 + 33) ^ 2 ) )    ")]
        [TestCase("exp(23 ^ 11 )")]
        [Test]
        public void ParseExpression_ResultIsFunction_Test(string expression)
        {
            var sin = ParseUtils.ParseExpression(expression);

            Assert.AreEqual(ExpressionType.Function, sin.Type);
        }

        [TestCase("-(( cos ( (  123 ^ 11 )) ))")]
        [TestCase(" -sin (1 ^ (8 * ((  ( ( 79797  ) )))))")]
        [TestCase(" - 56 ")]
        [TestCase("(-(( - 56 ) * x)) ")]
        [TestCase("-exp(23 ^ 11 )")]
        [Test]
        public void ParseExpression_ResultIsNegate_Test(string sExpression)
        {
            var expression = ParseUtils.ParseExpression(sExpression);

            Assert.IsTrue(expression.IsNegate);
        }

        [TestCase("-(( cos ( (  123 ^ 11 )) )) + 2")]
        [TestCase(" -sin (1 ^ (8 * ((  ( ( 79797  ) ))))) / 2")]
        [TestCase(" - 56 * (-23 +x)")]
        [TestCase("(-( - 56 ) * x) ")]
        [TestCase("-exp(23 ^sin( 11) )^  2 ")]
        [Test]
        public void ParseExpression_ResultIsNotNegate_Test(string sExpression)
        {
            var expression = ParseUtils.ParseExpression(sExpression);

            Assert.IsFalse(expression.IsNegate);
        }

        [TestCase("56*((-23)+x)")]
        [TestCase("exp(x^y)^2")]
        [TestCase("x+x*(2+y)")]
        [Test]
        public void ParseExpression_ResultToStringLikeInput_Test(string sExpression)
        {
            var expression = ParseUtils.ParseExpression(sExpression);

            Assert.AreEqual(sExpression, expression.ToString());
        }

        [TestCase("56 *(-23)")]
        [TestCase("exp(x^y)^2 ")]
        [TestCase("x+x*(2*y)")]
        [TestCase("0+x+x*(2+y)")]
        [Test]
        public void ParseExpression_ResultToStringUnlikeInput_Test(string sExpression)
        {
            var expression = ParseUtils.ParseExpression(sExpression);

            Assert.AreNotEqual(sExpression, expression.ToString());
        }
    }
}
